package com.cooper.resource.download;

import java.io.File;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

import android.util.Log;

import com.cooper.resource.download.DownloadResource.DownloadItem;
import com.cooper.resource.download.DownloadResource.PrepareException;
import com.cooper.scraper.HttpDownload;
import com.cooper.scraper.R;

public class DownloadResourceThread extends Thread {

	private DownloadStatus downloadStatus;

	private HttpDownload httpDownload;

	private Map<DownThread, Future<?>> threads = new HashMap<DownThread, Future<?>>();

	private ExecutorService threadPool;

	public DownloadResourceThread(HttpDownload httpDownload,
			DownloadStatus downloadStatus, int threadCount) {
		super();
		this.downloadStatus = downloadStatus;
		this.httpDownload = httpDownload;
		downloadStatus.threadCreate();
		//Runtime.getRuntime().availableProcessors() * THREAD_COUNT
		threadPool = Executors.newFixedThreadPool(threadCount);
		File fileSaveDir = downloadStatus.getDownloadResource()
				.getDownloadingSaveDir();
		if (!fileSaveDir.exists())
			fileSaveDir.mkdirs();
	}

	private void download() {
		for (DownloadItem downloadItem : downloadStatus.getDownloadItem()) {
			DownThread thread;
			if (downloadItem.isSupportRange()) {
				thread = new BlockDownThread(httpDownload, downloadStatus,
						downloadItem);
			} else {
				thread = new FileDownThread(httpDownload, downloadStatus,
						downloadItem);
			}
			threads.put(thread, threadPool.submit(thread));
		}

		while (!threadIsEmpty() && !threadPool.isShutdown()) {
			try {
				Thread.sleep(900);
			} catch (InterruptedException e) {
				terminatedAll();
				Log.d("DownloadResourceThread", "thread is terminated");
				return;
			}
		}
	}

	private boolean threadIsEmpty() {
		for (Future<?> task : threads.values()) {
			if (!task.isDone() && !task.isCancelled()) {
				return false;
			}
		}
		return true;
	}

	private void terminatedAll() {
		for (Future<?> task : threads.values()) {
			task.cancel(true);
		}
	}

	@Override
	public void run() {
		downloadStatus.beginDown();
		do {
			if (!Thread.currentThread().isInterrupted()
					&& (!downloadStatus.getDownloadResource().isPrepared() || downloadStatus
							.isRequestReLocation())) {
				try {
					downloadStatus.getDownloadResource().prepare(httpDownload);
					downloadStatus.downPrepared();
					if (!Thread.currentThread().isInterrupted())
						downloadStatus.saveDownInfo();
				} catch (PrepareException e) {
					if (!Thread.currentThread().isInterrupted())
						downloadStatus
								.downFail(
										e.isAnalyze() ? R.string.download_fail_for_prepare
												: R.string.download_fail_for_no_space,
										DownloadStatus.FAIL_FOR_PREPARE);
					break;
				} catch(Exception e){
					if (!Thread.currentThread().isInterrupted())
						downloadStatus
								.downFail(R.string.download_fail,
										DownloadStatus.FAIL_FOR_PREPARE);
					break;
				}

			}

			if (!Thread.currentThread().isInterrupted()) {
				downloadStatus.updateDownLen();
				download();
			}
		} while (!Thread.currentThread().isInterrupted()
				&& !downloadStatus.getDownloadResource().isFinish()
				&& downloadStatus.isRequestReLocation());
		downloadStatus.downComplete();
	}
}
